﻿using MvcApplication.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MvcApplication.CommonWebApi.Domain;
using MySql.Data.MySqlClient;
using System.Text.RegularExpressions;

namespace MvcApplication.CommonWebApi
{
    public static class CommonWebApiScriptLoader
    {
        const string ConfigPath = "App_Data/CommonApiConfig.xml";

        public static CommonApiConfig CommonApiConfig { get; private set; }

        public static List<ConnInfo> ConnInfos { get; private set; }

        public static List<Script> Scripts { get; private set; }

        static CommonWebApiScriptLoader()
        {
            CommonApiConfig = LoadCommonApiConfig();
            ConnInfos = LoadConnInfo();
            Scripts = LoadScripts();

            CommonApiConfig = null;
            //ConnInfos = null;

            CheckRepeatScript();
        }

        /// <summary>
        /// 加载配置文件
        /// </summary>
        /// <returns></returns>
        static CommonApiConfig LoadCommonApiConfig()
        {
            var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigPath);
            if (!File.Exists(path))
            {
                throw new BizException("未能找到通用Api配置文件~App_Data/CommonWebApi.xml");
            }

            var xmlContent = TridentUtil.LoadFileText(path);
            var result = XmlUtil.Deserialize<CommonApiConfig>(xmlContent);
            return result;
        }

        /// <summary>
        /// 加载连接串信息
        /// </summary>
        /// <returns></returns>
        static List<ConnInfo> LoadConnInfo()
        {
            var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, CommonApiConfig.ConnInfoPath);
            if (!File.Exists(path))
            {
                throw new BizException("未能找到通用Api连接串配置文件" + path);
            }

            var xmlContent = TridentUtil.LoadFileByte(path);
            var connInfo = XmlUtil.Deserialize<CommonConnInfo>(xmlContent);
            connInfo.ConnInfos.ForEach(t => t.ConnString.Trim());

            return connInfo.ConnInfos;
        }

        /// <summary>
        /// 加载脚本
        /// </summary>
        /// <returns></returns>
        static List<Script> LoadScripts()
        {
            var results = new List<Script>();
            var files = GetFilePaths();
            if (files.Count == 0)
            {
                return results;
            }

            foreach (var filePath in files)
            {
                var xmlContent = TridentUtil.LoadFileText(filePath);
                var scriptsList = XmlUtil.Deserialize<Scripts>(xmlContent);

                if (scriptsList != null && scriptsList.Script != null && scriptsList.Script.Count > 0)
                {
                    scriptsList.Script.ForEach(s =>
                    {
                        s.Text = s.Text.Trim();
                        s.Text = FilterStringEmpty(s.Text);
                        s.ConnInfo = GetConnInfo(s, scriptsList.DefaultConnId);
                        #region 参数处理
                        s.Params.ForEach(f =>
                        {
                            if (s.ConnInfo.Type == "MySql")
                            {
                                GetMySqlDbType(f);
                                f.Type = null;
                            }
                        });
                        #endregion
                        results.Add(s);
                    });
                }
            }
            return results;
        }

        /// <summary>
        /// 获取脚本文件路径列表
        /// </summary>
        /// <returns></returns>
        static List<string> GetFilePaths()
        {
            var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, CommonApiConfig.ScriptPath);
            if (!Directory.Exists(path))
            {
                throw new BizException("未能找到通用SQL脚本路径" + path);
            }
            var results = Directory.GetFiles(path, "*.xml", SearchOption.AllDirectories).ToList();
            return results;
        }

        /// <summary>
        /// 获取脚本的数据库连接串信息
        /// </summary>
        /// <param name="script"></param>
        /// <param name="defaultConnId"></param>
        /// <returns></returns>
        static ConnInfo GetConnInfo(Script script, int? defaultConnId)
        {
            if (!script.ConnId.HasValue && !defaultConnId.HasValue)
            {
                throw new BizException("脚本没有指定数据库连接串信息，Text：" + script.Text);
            }
            var connId = script.ConnId.HasValue ? script.ConnId.Value : defaultConnId.Value;
            var connInfo = ConnInfos.FirstOrDefault(t => t.Id == connId);
            if (connInfo == null)
            {
                throw new BizException("脚本指定数据库连接串信息不存在，ConnId：" + connId);
            }

            return connInfo;
        }

        /// <summary>
        /// 验证脚本是否有重复
        /// </summary>
        static void CheckRepeatScript()
        {
            foreach (var script in Scripts)
            {
                if (string.IsNullOrEmpty(script.CommonId))
                {
                    throw new BizException("CommonApi的CommonId为必填项，Text：" + script.Text);
                }

                script.CommonId = script.CommonId.Trim();
                if (script.CommonId.Contains(" "))
                {
                    throw new BizException("存在用CommId包含空格，CommonId：" + script.CommonId);
                }
            }

            var repeats = Scripts.GroupBy(t => t.CommonId).Where(t => t.Count() > 1).ToList();

            if (repeats.Count == 0) return;

            var commonIds = string.Join("|", repeats.Select(t => t.Key));
            throw new BizException("CommonWebApi存在重复的CommonId脚本，CommonId:" + commonIds);
        }

        /// <summary>
        /// 获取参数类型
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        static void GetMySqlDbType(ScriptParam param)
        {
            switch (param.Type)
            {
                case "string":
                    param.MySqlDbType = MySqlDbType.String;
                    break;
                case "int":
                    param.MySqlDbType = MySqlDbType.Int32;
                    break;
                case "long":
                    param.MySqlDbType = MySqlDbType.Int64;
                    break;
                case "float":
                    param.MySqlDbType = MySqlDbType.Float;
                    break;
                case "double":
                    param.MySqlDbType = MySqlDbType.Double;
                    break;
                case "decimal":
                    param.MySqlDbType = MySqlDbType.Decimal;
                    break;
                case "datetime":
                    param.MySqlDbType = MySqlDbType.DateTime;
                    break;
                case "bool":
                    param.MySqlDbType = MySqlDbType.Bit;
                    break;

                default: throw new BizException("不能识别Mysql参数类型");
            }
        }

        /// <summary>
        /// 过滤掉多余的字符串
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        static string FilterStringEmpty(string str)
        {
            var matches = Regex.Matches(str, @"'[\s\S]+?'");
            var temporary = new Dictionary<string, string>();
            var sqlTemplate = str;

            for (int i = 0; i < matches.Count; i++)
            {
                var match = matches[i];
                var key = "$" + i.ToString();
                var value = match.Groups[0].Value;
                str = str.Replace(value, key);
                temporary.Add(key, value);
            }

            var newStr = Regex.Replace(str, @"\s+", " ");

            foreach (var t in temporary)
            {
                newStr = newStr.Replace(t.Key, t.Value);
            }
            return newStr;
        }
    }
}
